Kubernetes 配置管理 ConfigMap
在 Kubernetes 中,一般有 ConfigMap 和 Secret 两种对象,可以用来做配置管理。
创建 ConfigMap
ConfigMap 通过键值对来存储信息,是个 namespace 级别的资源。在 kubectl 使用时,我们可以简写成 cm。
定义一个 CM 来测试 cm-demo-mix.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-demo-mix # 对象名字
namespace: demo # 所在的命名空间
data: # 这是跟其他对象不太一样的地方,其他对象这里都是 spec
# 每一个键都映射到一个简单的值
player_initial_lives: "3" # 注意这里的值如果数字的话,必须用字符串来表示
ui_properties_file_name: "user-interface.properties"
# 也可以来保存多行的文本
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
再定义一个 cm-demo-all-env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-demo-all-env
namespace: demo
data:
SPECIAL_LEVEL: very
SPECIAL_TYPE: charm
现在我们来创建这两个 ConfigMap:
$ kubectl create -f cm-demo-mix.yaml
$ kubectl create -f cm-demo-all-env.yaml
# 取得 ConfigMap 的信息
$ kubectl get cm -n demo
和 Pod 结合起来使用
Pod 必须和 ConfigMap 在同一个 namespace 下面,在创建 Pod 之前,请务必保证 ConfigMap 已经存在,否则 Pod 创建会报错。
创建一个 cm-demo-pod.yaml
文件
apiVersion: v1
kind: Pod
metadata:
name: cm-demo-pod
namespace: demo
spec:
containers:
- name: demo
image: busybox:1.28
command:
- 'bin/sh'
- '-c'
- 'echo PLAYER_INITIAL_LIVES=$PLAYER_INITIAL_LIVES && sleep 10000'
# 定义环境变量
env:
- name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
valueFrom:
configMapKeyRef:
name: cm-demo-mix # 这个值来自 ConfigMap
key: player_initial_lives # 需要取值的键
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: cm-demo-mix
key: ui_properties_file_name
# 可以将 configmap 中的所有键值对都通过环境变量注入容器中
envFrom:
- configMapRef:
name: cm-demo-all-env
# 可以将 configmap 中的某个键值对注入到文件中
volumeMounts:
- name: full-config # 这里是下面定义的 volume 名字
mountPath: '/config' # 挂载的目标路径
readOnly: true
- name: part-config
mountPath: /etc/game/
readOnly: true
volumes: # 可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
- name: full-config # 这是 volume 的名字
configMap:
name: cm-demo-mix # 提供你想要挂载的 ConfigMap 的名字
- name: part-config
configMap:
name: cm-demo-mix
items: # 也可以只挂载部分的配置
- key: game.properties
path: properties
在上面的这个例子中,几乎囊括了 ConfigMap 的几大使用场景:
- 命令行参数;
- 环境变量,可以只注入部分变量,也可以全部注入;
- 挂载文件,可以是单个文件,也可以是所有键值对,用每个键值作为文件名。
$ kubectl create -f cm-demo-pod.yaml
创建成功后,我们 exec 到容器中看看:
$ kubectl exec -it cm-demo-pod -n demo sh
可以看到注入进去的两个环境变量
$ ls -al /config/
可以看到挂载进去的文件,里面也包含了对应的配置文件
在上面 ls -alh /config/
后,我们看到挂载的文件中存在软链接,都指向了 ..data
目录下的文件。这样做的好处,是 kubelet 会定期同步检查已经挂载的 ConfigMap 是否是最新的,如果更新了,就是创建一个新的文件夹存放最新的内容,并同步修改 ..data
指向的软链接。
Secret 敏感数据
一般我们只把一些非敏感的数据保存到 ConfigMap 中,敏感的数据就要保存到 Secret 中了。
其实目前 Secret 的实现,就是 ConfigMap 把 value 用 base64 encode了一下,所以,其实不存在任何安全性,只要 decode 一下就能出现原来结果,相当于明文存储。
base64 这玩意儿都不能叫做加密,只能叫做编码,所以都不说 encrypt,而是 encode 和 decode。
当然,Kubernetes 社区有在计划对 Secret 进行下一步的安全性增强,当然这是后话了,截止目前为止,Secret 基本和 ConfigMap一样是明文存储。
可以用 Secret 来保存一些敏感的数据信息,比如密码、密钥、token 等。在使用的时候, 跟 ConfigMap 的用法基本保持一致,都可以用来作为环境变量或者文件挂载。
Kubernetes 自身也有一些内置的 Secret,主要用来保存访问 APIServer 的 service account token
通过命令行 help 可以看到 kubectl 能够创建多种类型的 Secret。
$ kubectl create secret -h
私有容器仓库的身份信息
先来创建一个 Secret 来保存访问私有容器仓库的身份信息
$ kubectl create secret -n demo docker-registry regcred \
--docker-server=yourprivateregistry.com \
--docker-username=allen \
--docker-password=mypassw0rd \
--docker-email=allen@example.com
再检查一下是否创建成功
$ kubectl get secret -n demo regcred
这里我们可以看到,创建出来的 Secret 类型是 kubernetes.io/dockerconfigjson
$ kubectl describe secret -n demo regcred
为了防止 Secret 中的内容被泄漏,kubectl get 和 kubectl describe 会避免直接显示密码的内容。但是我们可以通过拿到完整的 Secret 对象来进一步查看其数据:
$ kubectl get secret -n demo regcred -o yaml
这里我们发现 .dockerconfigjson
是一段乱码,我们用 base64 解压试试看:
$ kubectl get secret regcred -n demo --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
这实际上跟我们通过 docker login 后的 ~/.docker/config.json
中的内容一样。
至此,我们发现 Secret 和 ConfigMap 在数据保存上的最大不同。Secret 保存的数据都是通过 base64 加密后的数据。
普通的密码加密
平时使用较为广泛的还有另外一种 Opaque 类型的 Secret:
创建文件 secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
name: dev-db-secret
namespace: demo
type: Opaque
data: # 这里的值都是 base64 加密后的
password: UyFCXCpkJHpEc2I9
username: ZGV2dXNlcg==
$ kubectl create -f secret-demo.yaml
$ kubectl get secret -n demo dev-db-secret
或者我们也可以通过如下等价的 kubectl 命令来创建出来:
$ kubectl create secret generic dev-db-secret -n demo \
--from-literal=username=devuser \
--from-literal=password='S!B\*d$zDsb='
或通过文件来创建对象,比如:
$ echo -n 'username=devuser' > ./db_secret.txt
$ echo -n 'password=S!B\*d$zDsb=' >> ./db_secret.txt
$ kubectl create secret generic dev-db-secret -n demo \
--from-file=./db_secret.txt
有时候为了方便,也可以使用stringData,这样可以避免自己事先手动用 base64 进行加密。
apiVersion: v1
kind: Secret
metadata:
name: dev-db-secret
namespace: demo
type: Opaque
stringData:
password: devuser
username: S!B\*d$zDsb=
在 Pod 中使用 Secret:
# pod-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
namespace: demo
spec:
containers:
- name: demo-container
image: busybox:1.28
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- secretRef:
name: dev-db-secret
restartPolicy: Never
创建 Pod
$ kubectl create -f pod-secret.yaml
创建成功后,我们来查看下:
# 最后加的这个 -w 是为了持续查看
$ kubectl get pod -n demo secret-test-pod
$ kubectl logs -f -n demo secret-test-pod
我们可以在日志中看到命令 env 的输出,看到环境变量 username 和 password 已经正确注入。